package vip.ola.code.ctrl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import vip.ola.code.common.ctrl.BaseController;
import vip.ola.code.common.service.RpcCommonService;
import vip.ola.code.secruity.JwtUser;
import vip.ola.core.common.Exception.ServiceException;
import vip.ola.core.common.annotation.MethodLog;
import vip.ola.core.common.constant.Constant;
import vip.ola.core.common.constant.RetEnum;
import vip.ola.core.common.domain.BizResponse;
import vip.ola.core.common.domain.PayResponse;
import vip.ola.core.common.util.CodeImgUtil;
import vip.ola.core.common.util.LocalDateTimeUtil;
import vip.ola.core.common.util.MyLog;
import vip.ola.core.common.util.MySeq;
import vip.ola.core.entity.code.CodeInfo;
import vip.ola.core.entity.code.CodeUser;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;

import static vip.ola.core.common.constant.CodeConstant.*;
import static vip.ola.core.common.constant.Constant.CODE_ROLE_NORMAL;
import static vip.ola.core.common.constant.RetEnum.*;
import static vip.ola.core.common.constant.SysConfigConstant.*;
import static vip.ola.core.common.util.LocalDateTimeUtil.PATTERN_DATE_TIME;
import static vip.ola.core.common.util.LocalDateTimeUtil.PATTERN_TIME;

@RestController
@RequestMapping(Constant.CODE_CONTROLLER_ROOT_PATH + "/qr")
@PreAuthorize("hasRole('" + CODE_ROLE_NORMAL + "')")
public class QrCodeController extends BaseController {

    private final MyLog log = MyLog.getLog(QrCodeController.class);

    @Value("${qr.base-path}")
    private String basePath;
    @Value("${qr.preview-url}")
    private String previewUrl;

    private final String tempDir = "temp/";

    @Autowired
    private RpcCommonService rpcService;

    @RequestMapping("/list")
    public ResponseEntity<?> list(@DateTimeFormat(pattern = PATTERN_TIME) LocalTime collStartTime, @DateTimeFormat(pattern = PATTERN_TIME) LocalTime collEndTime,
                                  Integer codeType, Integer status, String username, String collName, String collThirdName, String collThirdAccount, BigDecimal minAmount, BigDecimal maxAmount) {
        CodeInfo codeInfo = getCodeInfo();
        codeInfo.setCodeType(codeType);
        codeInfo.setStatus(status);
        codeInfo.setUsername(username);
        codeInfo.setCollName(collName);
        codeInfo.setCollThirdName(collThirdName);
        codeInfo.setCollThirdAccount(collThirdAccount);
        codeInfo.setMinAmount(minAmount);
        codeInfo.setMaxAmount(maxAmount);
        codeInfo.setCollStartTime(collStartTime);
        codeInfo.setCollEndTime(collEndTime);
        IPage<CodeInfo> page = rpcService.codeInfoService.list(getPageIndex(), getPageSize(), codeInfo);
        return ResponseEntity.ok(PayResponse.buildPageSuccess(page));
    }

    @RequestMapping("/get")
    @ResponseBody
    public ResponseEntity<?> get(Long id) {
        CodeInfo codeInfo = getCodeInfo();
        codeInfo.setId(id);
        codeInfo = rpcService.codeInfoService.getByCodeInfo(codeInfo);
        return ResponseEntity.ok(PayResponse.buildSuccess(codeInfo));
    }

    private CodeInfo getCodeInfo() {
        JwtUser user = getUser();
        CodeInfo codeInfo = new CodeInfo();
        Integer type = user.getType();
        if (CODE_USER_TYPE.equals(type)) {
            codeInfo.setUserId(user.getId());
            codeInfo.setAgentId(user.getAgentId());
            codeInfo.setCodeBusId(user.getCodeBusId());
        } else if (CODE_AGENT_TYPE.equals(type)) {
            codeInfo.setAgentId(user.getId());
            codeInfo.setCodeBusId(user.getCodeBusId());
        } else if (CODE_CODE_SUB_TYPE.equals(type)) {
            codeInfo.setCodeBusId(user.getCodeBusId());
        } else if (CODE_CODE_TYPE.equals(type)) {
            codeInfo.setCodeBusId(user.getId());
        }
        codeInfo.setDeleted(LOGIC_NOT_DELETE);
        return codeInfo;
    }

    @MethodLog(remark = "添加二维码信息")
    @RequestMapping("/add")
    public ResponseEntity<?> save() throws IOException {
        String codePath = getStringRequired("codePath");
        CodeUser codeUser = rpcService.codeUserService.getById(getUser().getId());
        CodeInfo code = getCodeInfo();
        code.setUserId(codeUser.getId());
        code.setUsername(codeUser.getUsername());
        code.setRate(codeUser.getRate());
        code.setAgentRate(codeUser.getAgentRate());
        code.setCodeBusRate(codeUser.getCodeBusRate());
        code.setCollThirdAccount(getStringRequired("collThirdAccount"));
        code.setCollThirdName(getStringRequired("collThirdName"));
        code.setCollThirdId(getString("collThirdId"));
        code.setCollName(getStringRequired("collName"));
        code.setCodeType(getIntegerRequired("codeType"));
        code.setCollStartTime(LocalDateTimeUtil.str2LocalTime(getString("collStartTime")));
        code.setCollEndTime(LocalDateTimeUtil.str2LocalTime(getString("collEndTime")));
        JSONObject json = rpcService.rpcSysConfigService.getSysConfigObj(TYPE_CODE);
        ResponseEntity validate = validate(code, json, true, true);
        if (validate != null) {
            return validate;
        }
        code.setRemark(getString("remark"));
        code.setStatus(CODE_STATUS_OK);
        code.setWeight(json.getInteger(CODE_WEIGHT));
        code.setDayMaxAmount(json.getBigDecimal(CODE_DAY_MAX_AMOUNT));
        code.setDayMaxNum(json.getInteger(CODE_DAY_MAX_NUM));
        code.setCreateId(getUser().getId());
        code.setCreateTime(LocalDateTime.now());
        FileUtils.moveFile(new File(basePath + tempDir + codePath), new File(basePath + codePath));
        boolean isOk = rpcService.codeInfoService.save(code);
        return ResponseEntity.ok(BizResponse.build(isOk));
    }

    @MethodLog(remark = "编辑二维码信息")
    @RequestMapping("/edit")
    public ResponseEntity edit(CodeInfo code) throws IOException {
        String codePath = getStringRequired("codePath");
        JSONObject json = rpcService.rpcSysConfigService.getSysConfigObj(TYPE_CODE);
        CodeInfo codeByDB = rpcService.codeInfoService.getById(code.getId());
        boolean updateQr = false;
        if (codeByDB != null && !codeByDB.getCodePath().equals(code.getCodePath())) {
            updateQr = true;
        }
        ResponseEntity validate = validate(code, json, false, updateQr);
        if (validate != null) {
            return validate;
        }
        code.setWeight(null);
        code.setUpdateTime(LocalDateTime.now());
        if (updateQr) {
            FileUtils.moveFile(new File(basePath + tempDir + codePath), new File(basePath + codePath));
            new File(basePath + codeByDB.getCodePath()).delete();
        }
        boolean isOk = rpcService.codeInfoService.updateById(code);
        return ResponseEntity.ok(BizResponse.build(isOk));
    }

    private ResponseEntity validate(CodeInfo codeInfo, JSONObject sysConfig, boolean isAdd, boolean isTempPath) {
        String codePath = request.getParameter("codePath");
        if (StringUtils.isBlank(codePath)) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_NOT_QRCODE_ERROR));
        }
        String path = basePath;
        String context;
        try {
            if (isTempPath) {
                path += tempDir;
            }
            context = CodeImgUtil.decodeByPath(path + codePath);
        } catch (FileNotFoundException e) {
            log.error("解析二维码出错, path: " + path + codePath, e);
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_NOT_EXIST));
        }
        if (StringUtils.isBlank(context)) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_ERROR));
        }
        context = context.toLowerCase();
        if (CODE_TYPE_ALIPAY.equals(codeInfo.getCodeType())) {
            if (!context.startsWith(QR_ALIPAY_PREFIX)) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_TYPE_ERROR));
            }
        } else if (CODE_TYPE_WEXIN.equals(codeInfo.getCodeType())) {
            if (!context.startsWith(QR_WEXIN_PREFIX)) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_TYPE_ERROR));
            }
        } else if (CODE_TYPE_JUHE.equals(codeInfo.getCodeType())) {

        }
        if (isAdd) {
            CodeInfo byCodeUrl = rpcService.codeInfoService.getByCodeUrl(context);
            if (byCodeUrl != null) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_ALREADY_EXIST));
            }
        }
        BigDecimal minAmount = getBigDecimalRequired("minAmount");
        if (minAmount.compareTo(sysConfig.getBigDecimal(CODE_MIN_AMOUNT)) == -1) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_MIN_AMOUNT_ERROR));
        }
        BigDecimal maxAmount = getBigDecimalRequired("maxAmount");
        if (maxAmount.compareTo(sysConfig.getBigDecimal(CODE_MAX_AMOUNT)) == 1) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_MAX_AMOUNT_ERROR));
        }
        Integer dayMaxNum = getIntegerRequired("dayMaxNum");
        if (dayMaxNum > sysConfig.getInteger(CODE_DAY_MAX_NUM)) {
            return ResponseEntity.ok(BizResponse.build(CODE_DAY_MAX_NUM_ERROR));
        }
        BigDecimal dayMaxAmount = getBigDecimalRequired("dayMaxAmount");
        if (dayMaxAmount.compareTo(sysConfig.getBigDecimal(CODE_DAY_MAX_AMOUNT)) == 1) {
            return ResponseEntity.ok(BizResponse.build(CODE_DAY_MAX_AMOUNT_ERROR));
        }
        codeInfo.setTotalCollNum(null);
        codeInfo.setTotalCollAmount(null);
        codeInfo.setTotalCollProfit(null);
        codeInfo.setSucNum(null);
        codeInfo.setFailNum(null);
        codeInfo.setCodeUrl(context);
        codeInfo.setCodePath(codePath);
        if (isAdd) {
            codeInfo.setDayMaxNum(dayMaxNum);
            codeInfo.setDayMaxAmount(dayMaxAmount);
            codeInfo.setMinAmount(minAmount);
            codeInfo.setMaxAmount(maxAmount);
        }
        return null;
    }

    @RequestMapping("/disable")
    @MethodLog(remark = "停用二维码")
    public ResponseEntity disable(long id) {
        CodeInfo codeInfo = getCodeInfo();
        codeInfo.setId(id);
        codeInfo = rpcService.codeInfoService.getByCodeInfo(codeInfo);
        if (codeInfo == null) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_NOT_OPERATE));
        }
        if (!CODE_STATUS_OK.equals(codeInfo.getStatus())) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_STATUS_ERROR));
        }
        boolean isOk = rpcService.codeInfoService.updateStatus(id, CODE_STATUS_STOP);
        return ResponseEntity.ok(BizResponse.build(isOk));
    }

    @RequestMapping("/enable")
    @MethodLog(remark = "启用二维码")
    public ResponseEntity enable(long id) {
        CodeInfo codeInfo = getCodeInfo();
        codeInfo.setId(id);
        codeInfo = rpcService.codeInfoService.getByCodeInfo(codeInfo);
        if (codeInfo == null) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_NOT_OPERATE));
        }
        if (!CODE_STATUS_STOP.equals(codeInfo.getStatus())) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_STATUS_ERROR));
        }
        boolean isOk = rpcService.codeInfoService.updateStatus(id, CODE_STATUS_OK);
        return ResponseEntity.ok(BizResponse.build(isOk));
    }

    @RequestMapping("/del")
    @MethodLog(remark = "删除二维码")
    public ResponseEntity del(long id) {
        CodeInfo codeInfo = getCodeInfo();
        codeInfo.setId(id);
        codeInfo = rpcService.codeInfoService.getByCodeInfo(codeInfo);
        if (codeInfo == null) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_NOT_OPERATE));
        }
        boolean isOk = rpcService.codeInfoService.removeById(id);
        return ResponseEntity.ok(BizResponse.build(isOk));
    }

    @RequestMapping("/clean")
    @MethodLog(remark = "清理二维码收款数据")
    public ResponseEntity cleanCodeCollInfo() {
        JwtUser user = getUser();
        if (!CODE_CODE_TYPE.equals(user.getType())) {
            return ResponseEntity.ok(BizResponse.build(CODE_QRCODE_NOT_OPERATE));
        }
        boolean isOk = rpcService.codeInfoService.cleanCodeCollInfo(user.getId(), null, null);
        return ResponseEntity.ok(BizResponse.build(isOk));
    }

    @MethodLog(remark = "上传二维码")
    @RequestMapping("/upload")
    public ResponseEntity<?> uploadFile(@RequestParam(value = "file") MultipartFile upFile) {
        if (upFile.isEmpty()) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_OPERATION_FAIL));
        }
        try {
            long allowMaxSize = 1 * 1024 * 1024;
            if (allowMaxSize < upFile.getSize()) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_SIZE_ERROR));
            }
            boolean isImage = CodeImgUtil.isImage(upFile.getInputStream());
            if (!isImage) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_IMG_ERROR));
            }
            String context = CodeImgUtil.decodeByStream(upFile.getInputStream());
            if (StringUtils.isBlank(context)) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_ERROR));
            }
            CodeInfo byCodeUrl = rpcService.codeInfoService.getByCodeUrl(context);
            if (byCodeUrl != null) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.CODE_QRCODE_ALREADY_EXIST));
            }
            String fileName = upFile.getOriginalFilename();
            String ext = fileName.substring(fileName.lastIndexOf("."));
            String saveName = (MySeq.getUUID() + ext).toLowerCase();
            JwtUser user = getUser();
            String codePath = user.getCodeBusId() + File.separator + user.getAgentId() + File.separator + user.getId() + File.separator + saveName;
            String fullPath = basePath + tempDir + codePath;
            FileUtils.copyInputStreamToFile(upFile.getInputStream(), new File(fullPath));
            log.info("上传文件成功, codeBusId={}, agentId={}, userId={}, filePath={}", user.getCodeBusId(), user.getAgentId(), user.getId(), fullPath);
            // 返回数据
            Map<String, String> retMap = new HashMap<>(2);
            retMap.put("codePath", codePath);
            String url = previewUrl + tempDir + user.getCodeBusId() + "/" + user.getAgentId() + "/" + user.getId() + "/" + saveName;
            retMap.put("url", url);
            return ResponseEntity.ok(PayResponse.buildSuccess(retMap));
        } catch (ServiceException e) {
            log.error("商户ID:" + getUser().getId() + "," + e.getRetEnum().getMessage());
            return ResponseEntity.ok(BizResponse.build(e.getRetEnum()));
        } catch (IOException e) {
            log.error(e, "上传文件异常");
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_UNKNOWN_ERROR));
        }
    }

    @RequestMapping("/view")
    public ResponseEntity view(long id) {
        String codeUrl = rpcService.codeInfoService.getCodeUrlByCache(id);
        return ResponseEntity.ok(PayResponse.buildSuccess(codeUrl));
    }

}
